<?php
namespace Core\Libs\Reflection;

class ReflectionFile {

	final public static function &findNamespacesExternalInFile($caminho, $nameSpace = NULL, $idxToken = 0, $continuar = TRUE) {

		$retorno = FALSE;

		if(!is_array(&$caminho)) {

			if(!is_string(&$caminho) && !file_exists(&$caminho)) {

				return FALSE;
			}

			else {

				$arrayConteudoDoArquivo =& token_get_all(file_get_contents(&$caminho));
			}
		}

		else {

			$arrayConteudoDoArquivo =& $caminho;
		}

		if((!empty($nameSpace) || !$nameSpace) && $nameSpace != NULL) {

			extract(self::checkNamespacesInFile(&$arrayConteudoDoArquivo, &$nameSpace, 0, 'source'), EXTR_REFS & EXTR_OVERWRITE);

			if($retorno === FALSE) {

				return FALSE;
			}

			$continuar = FALSE;
		}

		while($arrayConteudoDoArquivo[$idxToken][0] !== T_CLOSE_TAG) {

			$idx = 0;

			if($arrayConteudoDoArquivo[$idxToken][0] === T_EXTENDS) {

				$possuiNameSpace = TRUE;

				if($arrayConteudoDoArquivo[$idxToken - 4][0] !== T_INTERFACE) {

					$arrayTiposDeNameSpaces[] = 'extends';
				}

				else {

					$arrayTiposDeNameSpaces[] = 'implements';
				}
			}

			elseif($arrayConteudoDoArquivo[$idxToken][0] === T_IMPLEMENTS) {

				$possuiNameSpace = TRUE;
				$arrayTiposDeNameSpaces[] = 'implements';
			}

			if($possuiNameSpace) {

				$idx = 2;

				while($arrayConteudoDoArquivo[$idxToken + $idx] !== '{') {

					if($arrayConteudoDoArquivo[$idxToken + $idx][0] !== T_IMPLEMENTS && $arrayConteudoDoArquivo[$idxToken + $idx] !== ',') {

						$nameSpacesClassePaiOuInterface .= $arrayConteudoDoArquivo[$idxToken + $idx][1];
					}

					elseif($arrayConteudoDoArquivo[$idxToken + $idx][0] === T_IMPLEMENTS || $arrayConteudoDoArquivo[$idxToken + $idx] === ',') {

						$arrayTiposDeNameSpaces[] = 'implements';
					}

					$idx++;
				}

				$possuiNameSpace = FALSE;

				if(!$continuar) {

					break;
				}
			}

			$idxToken += $idx + 1;				
		}

		unset($arrayConteudoDoArquivo);

		if(preg_match('/[\t\v\r\n\ ]+/', &$nameSpacesClassePaiOuInterface)) {

			return array_combine(preg_split('/[\t\v\r\n\ ]+/', preg_replace('/^[\t\v\r\n\ ]+|[\t\v\r\n\ ]+$/', '', &$nameSpacesClassePaiOuInterface)), &$arrayTiposDeNameSpaces);
		}

		if(!empty($nameSpacesClassePaiOuInterface)) {

			return array_combine(array($nameSpacesClassePaiOuInterface), &$arrayTiposDeNameSpaces);
		}

		return FALSE;
	}

	final public static function &checkNamespacesInFile($caminho, $nameSpace, $idxToken = 0, $retorno = FALSE) {

		if(!is_array(&$caminho)) {

			if(!is_string(&$caminho) && !file_exists(&$caminho)) {

				return FALSE;
			}

			else {

				$arrayConteudoDoArquivo =& token_get_all(file_get_contents(&$caminho));
			}
		}

		else {

			$arrayConteudoDoArquivo =& $caminho;
		}

		while($arrayConteudoDoArquivo[$idxToken][0] !== T_CLOSE_TAG) {

			if($arrayConteudoDoArquivo[$idxToken][0] === T_NAMESPACE) {

				$idx = 2;

				while($arrayConteudoDoArquivo[$idxToken + $idx] !== ';') {

					$nameSpaceEncontrado .= $arrayConteudoDoArquivo[$idxToken + $idx][1];
					$idx++;
				}

				$auxNameSpaceEncontrado = $nameSpaceEncontrado;
			}

			elseif($arrayConteudoDoArquivo[$idxToken][0] === T_CLASS || $arrayConteudoDoArquivo[$idxToken][0] === T_INTERFACE || $arrayConteudoDoArquivo[$idxToken][0] === T_ABSTRACT) {

				if($nameSpace === '\\'.$auxNameSpaceEncontrado.'\\'.$arrayConteudoDoArquivo[$idxToken + 2][1] || $nameSpace === $auxNameSpaceEncontrado.'\\'.$arrayConteudoDoArquivo[$idxToken + 2][1]) {

					if($retorno === 'source') {

						return array('arrayConteudoDoArquivo' => &$arrayConteudoDoArquivo, 'idxToken' => $idxToken + 2, 'retorno' => TRUE);
					}

					unset($arrayConteudoDoArquivo);
					return TRUE;
				}
			}

			$nameSpaceEncontrado = NULL;
			$idxToken++;
		}

		unset($arrayConteudoDoArquivo);

		if($retorno === 'source') {

			return array('retorno' => FALSE);
		}

		return FALSE;
	}
}

class ReflectionClass extends \Core\Libs\Reflection\ReflectionFile {

	protected $Class = NULL;
	protected $SubClass = NULL;
	protected $static = TRUE;
	private $parseObject = FALSE;
	private $parseClass = NULL;
	private $Object = NULL;
	private $namespace = NULL;
	private $isObject = TRUE;

	public function __construct($nameSpace = NULL, $object = FALSE, $reset = TRUE) {

		if(is_object(&$nameSpace)) {

			$className = get_class(&$nameSpace);
			$this->Object =& $nameSpace;
			$this->isObject = TRUE;

			if($object) {

				$this->Class = new \ReflectionObject($nameSpace);
				$this->parseObject = TRUE;
			}

			else {

				$this->Class = new \ReflectionClass($nameSpace);
				$this->parseObject = FALSE;
			}

			unset($nameSpace);
		}

		elseif(!empty($nameSpace)) {

			$className = $nameSpace;
			$this->isObject = FALSE;
			$this->Object = NULL;
			$this->Class = new \ReflectionClass($nameSpace);
		}

		if(is_null($this->namespace) || $reset === TRUE) {

			$this->namespace = $className;
		}
	}

	final public function isSetClass() {

		if(is_object($this->Class)) {

			return TRUE;
		}

		return FALSE;
	}

	final public function isObject() {

		return $this->isObject;
	}

	final public function setStatic($static = TRUE) {

		$this->static = $static;
	}

	final public function getStatic() {

		return $this->static;
	}

	final public function getClassName() {

		return $this->Class->getName();
	}

	final public function getClassPath() {

		return $this->Class->getFileName();
	}

	final public function &init($nameSpace, $object = FALSE, $return = TRUE, $reset = TRUE) {

		$this->__construct(&$nameSpace, $object, $reset);

		if($return === TRUE) {

			return $this;
		}
	}

	final public function setObject($object) {

		$className = $this->Class->getName();

		if(is_object($object) && $object instanceof $className) {

			$this->Object =& $object;
			$this->isObject = TRUE;
		}

		return $this;
	}

	final public function &getObject() {

		return $this->Object;
	}

	final public function setClass($nameSpace) {

		$this->Class->__construct($nameSpace);
	}

	final public function getClass() {

		return $this->Class;
	}

	public function getMethod($method = NULL) {

		if(!empty($method) && $this->isObject) {

			return new \Core\Libs\Reflection\ReflectionMethod($this->Object, $method, $this->parseObject, TRUE);
		}

		return NULL;
	}

	public function getProperty($property) {

		if(!empty($property) && $this->isObject) {

			return new \Core\Libs\Reflection\ReflectionProperty($this->Object, $property, $this->parseObject, $this->parseClass, TRUE);
		}

		return NULL;
	}

	final public function hasProperty($property) {

		return $this->Class->hasProperty($property);
	}

	final public function hasMethod($method) {

		return $this->Class->hasProperty($method);
	}

	final public function getNamesOfMethodsInClass($arrayClassesToSearch = array(), $modifiers = NULL, $strict = TRUE, $flagFoundOrNotFound = FALSE) {

		$arrayMethods =& $this->Class->getMethods();
		$arrayFiltered = array();
		$arrayModifiersOfMethod = array();
		$arrayIntersetModifiers = array();
		$countModifiersOfMethod = 0;
		$countModifiers = 0;

		if(!is_array(&$arrayClassesToSearch)) {

			if(!empty($arrayClassesToSearch)) {

				$arrayClassesToSearch = array($arrayClassesToSearch);
			}

			else {

				$arrayClassesToSearch = array($this->namespace);
			}			
		}

		if(empty($modifiers)) {

			$strict = FALSE;
			$modifiers = array();
		}

		elseif(!is_array(&$modifiers)) {

			if(is_string($modifiers)) {

				$modifiers =& preg_split('/[^a-z]+/i', &$modifiers);
			}

			else {

				$modifiers =& \Reflection::getModifierNames(&$modifiers);
			}
		}

		$countModifiers =& count(&$modifiers);

		foreach($arrayMethods as $method){

			$arrayModifiersOfMethod =& \Reflection::getModifierNames($method->getModifiers());
			$countModifiersOfMethod =& count(&$arrayModifiersOfMethod);

			foreach($arrayClassesToSearch as $classesToSearch) {

				if($classesToSearch{0} === '\\') {

					$classesToSearch = substr(&$classesToSearch, 1);
				}

				if((($flagFoundOrNotFound === TRUE && $method->class === $classesToSearch) || ($flagFoundOrNotFound === FALSE && $method->class !== $classesToSearch))) {

					$countIntersetModifiers =& count(array_intersect(&$arrayModifiersOfMethod, &$modifiers));

					if(($countIntersetModifiers >= $countModifiers && $strict === FALSE) || ($countModifiersOfMethod === $countModifiers && $strict === TRUE) || ($countIntersetModifiers === 0 && $strict === NULL)) {

						$arrayFiltered[$method->class][] = $method->name;
					}
				}
			}
		}

		unset($arrayMethods, $arrayClassesToSearch, $arrayModifiersOfMethod, $arrayIntersetModifiers, $method, $classesToSearch, $modifiers);
		return $arrayFiltered;
	}

	public function getDefaultProperties() {

		return $this->Class->getDefaultProperties();
	}

	public function getDefaultPropertiesRecursive() {

		$Class = $this->Class;

		do {

			$arrayProps = $Class->getDefaultProperties();
	
			if(!empty($arrayProps)) {
	
				$arrayAllProps[$Class->getName()] =& array_merge((array)$arrayAllProps[$Class->getName()], $arrayProps);
			}

			$Class = $Class->getParentClass();

		} while($Class);

		unset($arrayProps, $Class);

		if(count($arrayAllProps)) {

			$arrayAllProps =& array_reverse(&$arrayAllProps);
		}

		return $arrayAllProps;
	}

	final public function hasPropertiesInClass($arrayPropertiesNames = array(), $context = NULL, $isStatic = NULL, $isDefault = NULL) {

		if(!is_array($arrayPropertiesNames)) {

			$arrayPropertiesNames = array($arrayPropertiesNames);
		}

		$arrayPropertiesFound = array();

		foreach($arrayPropertiesNames as $propertyName) {

			if($this->Class->hasProperty($propertyName)) {

				$property = $this->Class->getProperty($propertyName);

				if($property->class === $this->Class->getName()) {

					if(empty($context) || (($property->isPrivate() && $context === 'private') || ($property->isProtected() && $context === 'protected') || ($property->isPublic() && $context === 'public'))) {

						$pass = TRUE;
					}

					if($pass === TRUE && ($isStatic === NULL || (($property->isStatic() && $isStatic) || (!$property->isStatic() && !$isStatic))) && ($isDefault === NULL || ($property->isDefault() && $isDefault) || (!$property->isDefault() && !$isDefault))) {

						$arrayPropertiesFound[] = $property->getName();
						$pass = FALSE;
					}

					else {

						$pass = FALSE;
					}
				}
			}
		}

		unset($arrayPropertiesNames, $property, $propertyName, $context, $isStatic, $isDefault);

		return $arrayPropertiesFound;
	}

	final public function getPropertiesRecursive($className = NULL, $reverse = TRUE, $first = FALSE) {

		$arrayAllProperties = array();
		$arrayProperties = array();
		$arrayValues = array();
		$Class = $this->Class;

		do {

			if(empty($className) || (!empty($className) && $Class->getName() === $className)) {

				$arrayProperties = $Class->getProperties();

				foreach($arrayProperties as $property) {

					$property->setAccessible(TRUE);

					if($property->isDefault()) {

						$this->parseClass = $property->class;
					}

					else {

						$this->parseClass = NULL;
					}

					$arrayValues = $this->getProperty($property->getName())->getValues($reverse, $first);

					if(!empty($arrayValues)) {

						foreach($arrayValues as $namespace => $class) {

							foreach($class as $context => $configProperty) {

								$arrayAllProperties[$namespace][$context] = array_merge((array)$arrayAllProperties[$namespace][$context], $configProperty);
							}
						}
					}
				}
			}

			$Class = $Class->getParentClass();

		} while($Class);

		unset($arrayProperties, $arrayValues, $context, $Class, $class, $configProperty, $namespace);

		return $arrayAllProperties;
	}

	final public function mergePropertiesRecursive($var1 = NULL, $var2 = NULL, $reverse = FALSE, $first = FALSE) {

		if(empty($var2)) {

			$varToMerge =& $var1;
			$object =& $this->Object;
		}

		elseif(!is_object($var2)) {

			$varToMerge =& $var1;
			$object =& $this->Object;
			$reverse = $var2;
			$first = $reverse;
		}

		else {

			$object =& $var1;
			$varToMerge =& $var2;
		}

		if(!empty($varToMerge)) {

			if(is_object($varToMerge)) {

				$ReflectionObject = new \Core\Libs\Reflection\ReflectionObject(&$varToMerge);			
				$arrayAllPropertiesValues =& $ReflectionObject->getPropertiesRecursive(FALSE, FALSE);
			}

			elseif(is_array($varToMerge)) {

				$arrayAllPropertiesValues = $varToMerge;
			}

			else {

				return FALSE;
			}

			$Class = $this->Class;

			do {

				$arrayPropertiesValuesOfClass = $arrayAllPropertiesValues[$Class->getName()];

				if(is_array($arrayPropertiesValuesOfClass)) {

					foreach($arrayPropertiesValuesOfClass as $arrayPropertiesValues) {

						foreach($arrayPropertiesValues as $propertyName => $propertyValue) {

							$property = $Class->getProperty($propertyName);
							$property->setAccessible(TRUE);
							$property->setValue(&$object, &$propertyValue['value']);
						}					
					}
				}

				$Class = $Class->getParentClass();

			} while($Class);
		}

		else {

			return FALSE;
		}

		unset($Class, $varToMerge, $ReflectionObject, $object, $var1, $var2, $arrayAllPropertiesValues, $arrayPropertiesValues, $arrayPropertiesValuesOfClass, $property, $propertyName, $propertyValue);
	}

	final public function &getNamespaces($keys = TRUE) {

		if($keys) {

			return array_keys(array_merge(array($this->getClassName() => $this->getClassName()), $this->getParents(), $this->getInterfaces()));
		}

		return array_merge(array($this->getClassName() => $this->getClassName()), $this->getParents(), $this->getInterfaces());
	}

	final public function &getParents() {

		return class_parents($this->getClassName());
	}

	final public function &getInterfaces() {

		return class_implements($this->getClassName());
	}
}

class ReflectionObject extends \Core\Libs\Reflection\ReflectionClass {

	public function __construct($object) {

		parent::__construct(&$object, TRUE);
	}
}

class ReflectionMethod extends \Core\Libs\Reflection\ReflectionClass {

	private $Method = NULL;
	private $parseObject = FALSE;
	private $Object = NULL;
	private $isObject = FALSE;
	private $className = NULL;
	private $methodName = NULL;
	private $accessible = TRUE;

	public function __construct($class, $method, $object = FALSE, $parent = TRUE) {

		$this->parseObject = $object;

		if(is_object($class)) {

			$this->Object = $class;
			$this->className = get_class($class);
			$this->isObject = TRUE;
		}

		else {

			$this->isObject = FALSE;
		}

		if($parent === TRUE) {

			parent::__construct($class, $this->parseObject, TRUE);
		}

		try {

			$this->methodName = $method;		
			$this->Method =& new \ReflectionMethod($this->Object, $method);
		}

		catch(\ReflectionException $e) {

			throw \Core\Uses\Exception('Error: Falha ao invocar o método: ' . $this->methodName . ', da Classe: ' . $this->className, E_ERROR, 100, $this->Class->getFileName(), $this->Class->getStartLine(), $e->getMessage());
		}
	}

	final public function setMethod($method) {

		if(!empty($method)) {

			$this->__construct($this->Object, $method, $this->parseObject, TRUE);
		}

		return $this;
	}

	final public function getMethod() {

		return $this->Method;
	}

	final public function setAccessible($accessible) {

		$this->accessible = $accessible;
		return $this;
	}

	final public function isAccessible() {

		return ($this->Method->isPrivate || $this->Method->isProtected) ? FALSE : TRUE;
	}

	final public function invoke($params = array()) {

		if(!$this->isObject) {

			return NULL;
		}

		if(!is_array($params)) {

			$params = array($params);
		}

		try {

			if($this->accessible) {

				$this->Method->setAccessible(TRUE);
			}

			return $this->Method->invokeArgs($this->Object, &$params);
		}

		catch(\ReflectionException $e) {

			throw \Core\Uses\Exception('Error: Falha ao invocar o método: ' . $this->methodName . ', da Classe: ' . $this->className, E_ERROR, 100, $this->Class->getFileName(), $this->Class->getStartLine(), $e->getMessage());
		}

		return FALSE;
	}

	final public function invokeRecursive($params = array(), $reverse = TRUE, $first = FALSE) {

		if(!$this->isObject) {

			return NULL;
		}

		if(!is_array($params)) {

			$params = array($params);
		}

		$arrayReturnOfMethods = array();
		$arrayMethods = array();

		$Class = $this->Class;
		$Method = $this->Method;

		do {

			if($Class->hasMethod($this->methodName) && $Method->class === $Class->getName()) {

				if($this->accessible) {

					$Method->setAccessible(TRUE);
				}

				$arrayMethods[] = $Method;
			}

			$Class = $Class->getParentClass();

			if($Class && $Class->hasMethod(&$this->methodName)) {

				$Method = $Class->getMethod($this->methodName);
			}

		} while($Class);

		if(count($arrayMethods)) {

			if($reverse) {

				$arrayMethods =& array_reverse(&$arrayMethods);
			}

			if($first) {

				$arrayMethods = array(key(&$arrayMethods) => current(&$arrayMethods));
			}
		}

		foreach($arrayMethods as $method) {

			try {

				$arrayReturnOfMethods[$method->class] = $method->invokeArgs($this->Object, &$params);
			}

			catch(\ReflectionException $e) {

				throw \Core\Uses\Exception('Error: Falha ao invocar o método: ' . $this->methodName . ', da Classe: ' . $this->className, E_ERROR, 100, $this->Class->getFileName(), $this->Class->getStartLine(), $e->getMessage());
			}
		}

		unset($arrayMethods, $params, $first, $reverse, $Class, $Method, $method);

		return $arrayReturnOfMethods;
	}

	final public function invokeOfClass($callOfClass = NULL, $params = array()) {

		if(!$this->isObject) {

			return NULL;
		}

		if(empty($callOfClass)) {

			$callOfClass = $this->className;
		}

		$return = NULL;

		if($callOfClass{0} === '\\') {

			$callOfClass =& substr(&$callOfClass, 1);
		}

		if(!is_array($params)) {

			$params = array($params);
		}

		$Class = $this->Class;
		$Method = $this->Method;

		do {

			if($Class->hasMethod($this->methodName) && $Method->class === $callOfClass) {

				if($this->accessible) {

					$Method->setAccessible(TRUE);
				}

				try {

					$return =& $Method->invokeArgs($this->Object, &$params);
				}

				catch(\ReflectionException $e) {

					throw \Core\Uses\Exception('Error: Falha ao invocar o método: ' . $this->methodName . ', da Classe: ' . $this->className, E_ERROR, 100, $this->Class->getFileName(), $this->Class->getStartLine(), $e->getMessage());
				}

				break;
			}

			$Class = $Class->getParentClass();

			if($Class && $Class->hasMethod(&$this->methodName)) {

				$Method = $Class->getMethod($this->methodName);
			}

		} while($Class);

		unset($Class, $Method, $callOfClass, $params);

		return $return;
	}
}

class ReflectionProperty extends \Core\Libs\Reflection\ReflectionClass {

	private $Property = NULL;
	private $parseObject = FALSE;
	private $parseClass = NULL;
	private $Object = NULL;
	private $isObject = FALSE;
	private $className = NULL;
	private $propertyName = NULL;
	private $accessible = TRUE;

	public function __construct($class, $property, $object = FALSE, $name = NULL, $parent = TRUE) {

		$this->parseObject = $object;

		if(is_object($class)) {

			$this->Object = $class;
			$this->className = get_class($class);
			$this->isObject = TRUE;
		}

		else {

			$this->className = $class;
			$this->isObject = FALSE;
		}

		if($parent === TRUE) {

			parent::__construct($class, $object, TRUE);
		}

		try {

			if(empty($name)) {

				$this->Property =& new \ReflectionProperty($this->Object, $property);
				$this->parseClass = NULL;
			}

			else {

				$this->Property =& new \ReflectionProperty($name, $property);
				$this->parseClass = $name;
			}

			$this->propertyName = $property;
		}

		catch(\ReflectionException $e) {
			
			throw \Core\Uses\Exception('Error: Propriedade: ' . $property . ', não existente na Classe: ' . $this->className, E_ERROR, 100, $this->Class->getFileName(), $this->Class->getStartLine(), $e->getMessage());
		}
	}

	final public function setProperty($property) {

		if(!empty($property)) {

			$this->__construct($this->Object, $property, $this->parseObject, TRUE);
		}

		return $this;
	}

	final public function getProperty() {

		return $this->Property;
	}

	final public function setAccessible($accessible) {

		$this->accessible = $accessible;
		return $this;
	}

	final public function isAccessible() {

		return ($this->Property->isPrivate || $this->Property->isProtected) ? FALSE : TRUE;
	}

	final public function getValues($reverse = TRUE, $first = FALSE, $inClass = FALSE) {

		if($this->isObject) {

			$Class = $this->Class;
			$Property = $this->Property;

			do {

				if($Class->hasProperty(&$this->propertyName)) {

					$Property->setAccessible($this->accessible);

					if($Property->isPrivate()) {

						$arrayProps[$Class->getName()]['private'][$this->propertyName] = array('value' => $Property->getValue(&$this->Object), 'static' => $Property->isStatic(), 'default' => $Property->isDefault());
					}

					elseif($Property->isProtected()) {

						$arrayProps[$Class->getName()]['protected'][$this->propertyName] = array('value' => $Property->getValue(&$this->Object), 'static' => $Property->isStatic(), 'default' => $Property->isDefault());
					}

					else {

						$arrayProps[$Class->getName()]['public'][$this->propertyName] = array('value' => $Property->getValue(&$this->Object), 'static' => $Property->isStatic(), 'default' => $Property->isDefault());
					}
				}

				$Class = $Class->getParentClass();

				if($Class && $Class->hasProperty(&$this->propertyName)) {

					$Property = $Class->getProperty($this->propertyName);
				}

			} while($Class);

			if(count(&$arrayProps)) {

				if($reverse) {

					$arrayProps =& array_reverse(&$arrayProps);
				}

				if($first) {

					$arrayProps = array(key(&$arrayProps) => current(&$arrayProps));
				}
			}

			else {

				$arrayProps = array();
			}

			unset($Class, $Property, $first, $reverse);

			return $arrayProps;
		}

		return array();
	}

	final public function getValue($context = NULL, $isStatic = NULL, $nameSpace = NULL, $reverse = TRUE, $first = FALSE) {

		$arrayProperty =& $this->getValues(&$reverse, &$first, NULL);

		if(!$arrayProperty) {

			return NULL;
		}

		foreach($arrayProperty as $key => $property) {

			if(empty($context) || $context === $key) {

				foreach($property as $ns => &$v) {

					if((($nameSpace !== NULL && $nameSpace === $ns) || $nameSpace === NULL) && (empty($isStatic) || ($isStatic === TRUE && $v['static'] || $isStatic === FALSE && !$v['static']))) {

						unset($arrayProperty, $property, $nameSpace, $ns, $key, $context, $first, $reverse);
						$v =& current(&$v);
						return $v['value'];
					}
				}
			}
		}

		return NULL;
	}

	final public function setValue($value = NULL, $context = NULL, $isStatic = NULL, $nameSpace = NULL, $reverse = TRUE, $first = FALSE) {

		if(!$this->isObject) {

			return NULL;
		}

		$Class = $this->Class;
		$Property = $this->Property;

		do {

			if((($context !== NULL && ($context === 'private' && $Property->isPrivate() || $context === 'protected' && $Property->isProtected() || $context === 'public' && $Property->isPublic())) || $context === NULL) && (($nameSpace !== NULL && $nameSpace === $Property->class) || $nameSpace === NULL) && (empty($isStatic) || ($isStatic === TRUE && $Property->isStatic() || $isStatic === FALSE && !$Property->isStatic()))) {

				$Property->setAccessible($this->accessible);

				try {

					$Property->setValue(&$this->Object, &$value);
					break;
				}

				catch(\ReflectionException $e) {

					throw \Core\Uses\Exception('Error: Não foi possível setar o valor à propriedade. Property: ' . $this->propertyName, 50, $Class->getFileName(), $Class->getStartLine(), $e->getMessage());
				}
			}

			$Class = $Class->getParentClass();

			if($Class && $Class->hasProperty(&$this->propertyName)) {

				$Property = $Class->getProperty($this->propertyName);
			}

		} while($Class);

		unset($Class, $Property, $nameSpace, $isStatic, $context, $first, $reverse, $e);
	}

	final private function mergeValuesOfMvcRequest($arrayProps, $checkAlias = TRUE) {

		$arrayPropValues = array();

		foreach($arrayProps as $type => $prop) {

			foreach($prop as $arrayValues) {

				foreach($arrayValues as $propertyName => $values) {

					foreach($values['value'] as $key => $value) {

						if(!is_numeric($key) && !array_key_exists($key, &$arrayPropValues) && !empty($value)) {

							$arrayPropValues[$key] = $value;

							if($checkAlias === TRUE && !empty($value['alias']) && !array_key_exists($value['alias'], &$arrayPropValues)) {

								$arrayPropValues[$value['alias']] = $key;
							}
						}

						elseif(!is_array(&$value) && !array_key_exists(&$value, &$arrayPropValues) && !in_array(&$value, &$arrayPropValues) && !empty($value)) {

							$arrayPropValues[] = $value;
						}
					}
				}
			}
		}

		return $arrayPropValues;
	}

	final public function mergedValuesOfMvcRequest($reverse = TRUE, $first = FALSE) {

		return $this->mergeValuesOfMvcRequest($this->getValues(&$reverse, &$first, NULL));
	}

	final public function mergePropertyValuesOfEqualType() {

		
	}

	final public function mergedPropertyValuesOfEqualType() {

		
	}
}
?>